package com.dkts.oil.web.vo.request;

import com.alibaba.fastjson.JSONObject;
import com.dkts.oil.converter.GeometryConverter;
import com.dkts.oil.exception.OilException;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.io.ParseException;

import java.util.List;

@Data
public class SiteSelectionRequest {
    @Schema(description  = "中心点坐标(jc中心点)")
    public AddressPoint centerPoint;

    @Schema(description  = "自定义区域（jc边界json）",example = "{ \"type\": \"Feature\", \"properties\": { \"id\": 3, \"name\": \"杭州萧山国际机场\" }, \"geometry\": { \"type\": \"MultiPolygon\", \"coordinates\": [ [ [ [ 120.401862649356715451, 30.237778607536796471 ], [ 120.446583467371425513, 30.255615234375031974 ], [ 120.456406537224367526, 30.253030215992676943 ], [ 120.4549201516545196, 30.246179917279444993 ], [ 120.445484834558925513, 30.247343175551502981 ], [ 120.4494269875920196, 30.242948644301502981 ], [ 120.459767061121425513, 30.240686753216944993 ], [ 120.454273897058925513, 30.235128963694887005 ], [ 120.406095616957813377, 30.214804256663640558 ], [ 120.39750043083648734, 30.236130658318053577 ], [ 120.401862649356715451, 30.237778607536796471 ] ] ] ] } }")
    public String  pointGeoJson;

    @Schema(description  = "xz范围区域(与jc中心点距离)" ,example = "50000")
    public Double rangePointDistance;

    @Schema(description  = "区域配置")
    public AreaConfig areaConfig;

    @Schema(description  = "约束条件")
    public ConstraintConfig constraintConfig;

    @Schema(description  = "自定义区域条件,最多不能超过五个")
    public List<CustomAreaRequest> customArea;

    @Schema(hidden = true)
    public  Point point;

    @Schema(hidden = true)
    public  Geometry pointAreaPolygon;
    @Schema(hidden = true)
    private  JSONObject prop;

    @Schema(hidden = true)
    private Geometry defaultPolygon;


    public void check() throws ParseException {
        if (centerPoint==null){
            throw new OilException("区域配置不能为空");
        }
        centerPoint.check();
        point = GeometryConverter.locationtechGeometryFactory.createPoint(new Coordinate(centerPoint.lon, centerPoint.lat));
        if (pointGeoJson == null || pointGeoJson.isEmpty()){
            throw new IllegalArgumentException("区域配置不能为空");
        }


        try {
            JSONObject jsonObject = JSONObject.parseObject(pointGeoJson);
            this.prop = jsonObject.getJSONObject("properties");
            if (prop == null){
                this.prop = new JSONObject();
            }
           pointAreaPolygon = GeometryConverter.geoJsonToGeometry(jsonObject.getJSONObject("geometry").toJSONString());

            defaultPolygon = GeometryConverter.geoJsonToGeometry(jsonObject.getJSONObject("geometry").toJSONString());
        }catch (Exception e){
            throw new IllegalArgumentException("区域配置json格式错误");
        }

        if (!pointAreaPolygon.contains(point)){
            throw new IllegalArgumentException("中心点不在区域内部");
        }

        if (rangePointDistance == null || rangePointDistance <= 0){
            throw new IllegalArgumentException("区域配置不能为空,而且必须大于0");
        }
        if (areaConfig == null){
            throw new IllegalArgumentException("区域配置不能为空");
        }
        areaConfig.checkTotalArea();

        if (constraintConfig != null){
            constraintConfig.check(rangePointDistance);
        }

//        if (customArea != null && customArea.size() > 5){
//            throw new OilException("自定义区域条件不能超过5个");
//        }

        if (customArea != null){
            for (CustomAreaRequest customAreaRequest : customArea) {
                customAreaRequest.check(rangePointDistance,this.pointAreaPolygon);
            }
        }


    }

    @Schema(description  = "区域配置")
    @Data
    public static class AddressPoint {
        @Schema(description  = "经度" ,example = "120.427518489627801")
        public Double lon;

        @Schema(description  = "纬度" ,example = "30.236035984680367")
        public Double lat;

        public void check(){
            if(lon==null||lat==null){
                throw new IllegalArgumentException("中心点坐标不能为空");
            }
        }
    }

    @Data
    @Schema(description = "自定义选址区域请求参数")
    public  static class CustomAreaRequest {
        @Schema(description  = "自定义区域边界",example = "{ \"type\": \"Feature\", \"properties\": { \"layer\": \"新建临时图层5\", \"path\": \"Polygon?crs=EPSG:4326&uid={75a41639-3b82-4c4c-8e01-0411d2cb193a}\" }, \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [ [ [ 120.430094960810749, 30.244111235485907 ], [ 120.436901110733871, 30.24607454796373 ], [ 120.441438544015952, 30.241275339684606 ], [ 120.43790458155587, 30.237261456396613 ], [ 120.430182219143106, 30.240010093865564 ], [ 120.430094960810749, 30.244111235485907 ] ] ] } }")
        private String boundGeoJson;


        @Schema(description  = "自定义区域距离 单位米" ,example = "20")
        private Double distance;

        @Schema(hidden = true)
        private  Geometry customAreaPolygon;

        @Schema(description = "属性",hidden = true)
        private  JSONObject prop;

        public void check(Double rangePointDistance,Geometry geometry) {
            if (boundGeoJson == null || boundGeoJson.isEmpty()){
                throw new IllegalArgumentException("自定义区域边界不能为空");
            }
            if (distance == null || distance <= 0){
                throw new IllegalArgumentException("自定义区域距离不能小于0");
            }
            if (distance > rangePointDistance){
                throw new IllegalArgumentException("自定义区域距离不能大于xz范围区域");
            }

            try {
                JSONObject jsonObject = JSONObject.parseObject(boundGeoJson);
                this.prop = jsonObject.getJSONObject("properties");
                if (prop == null){
                    this.prop = new JSONObject();
                }
                this.customAreaPolygon = GeometryConverter.geoJsonToGeometry(jsonObject.getJSONObject("geometry").toJSONString());
            }catch (Exception e){
                throw new IllegalArgumentException("区域配置json格式错误");
            }
            if (!geometry.contains(customAreaPolygon)){
                throw new IllegalArgumentException("自定义区域边界不在区域内部");
            }
        }
    }

    @Data
    public static class AreaConfig {
        /** 总库区面积（㎡） */
        @Schema(description  = "总库区面积（㎡）" ,example = "20000")
        private Double totalArea;
        /** 转运站面积（㎡） */
        @Schema(description  = "转运站面积（㎡）" ,example = "4000")
        private Double transferStationArea;
        /** 储备库面积（㎡） */
        @Schema(description  = "储备库面积（㎡）" ,example = "5000")
        private Double reserveDepotArea;
        /** 消耗库面积（㎡） */
        @Schema(description  = "消耗库面积（㎡）" ,example = "3000 ")
        private Double consumptionDepotArea;
        /** 外场供油中心面积（㎡） */
        @Schema(description  = "外场供油中心面积（㎡）" ,example = "300")
        private Double fuelSupplyCenterArea;

        /** 校验面积总和是否合法 */
        public boolean check() {
            if (totalArea == null || totalArea <= 0){
                throw new RuntimeException("总库区面积不能小于0");
            }
            if (transferStationArea == null || transferStationArea <= 0){
               throw new IllegalArgumentException("转运站面积不能小于0");
            }
            if (reserveDepotArea == null || reserveDepotArea <= 0){
                throw new IllegalArgumentException("储备库面积不能小于0");
            }
            if (consumptionDepotArea == null || consumptionDepotArea <= 0){
                throw new IllegalArgumentException("消耗库面积不能小于0");
            }
            if (fuelSupplyCenterArea == null || fuelSupplyCenterArea <= 0){
                throw new IllegalArgumentException("外场供油中心面积不能小于0");
            }
            double sum = (transferStationArea != null ? transferStationArea : 0)
                    + (reserveDepotArea != null ? reserveDepotArea : 0)
                    + (consumptionDepotArea != null ? consumptionDepotArea : 0)
                    + (fuelSupplyCenterArea != null ? fuelSupplyCenterArea : 0);
            return sum <= (totalArea != null ? totalArea : 0);
        }

        public void checkTotalArea() {
            if (!check()) {
                throw new IllegalArgumentException("各库区面积之和超出总库区面积限制！");
            }
        }
    }

    @Data
    public static class ConstraintConfig {
        /**
         * 与水库最小距离（单位：米）
         * 要求库区位置到最近的水库边缘距离，不能小于这个值。
         * 比如：500 米以内不能建库。
         */
        @Schema(description  = "与水库最小距离（单位：米）" ,example = "30")
        private Double minDistanceToReservoir;

        /**
         * 与湖泊最小距离（单位：米）
         * 要求库区位置到最近湖泊边缘的最小距离。
         * 比如：300 米以内禁止建库。
         */
        @Schema(description  = "与湖泊最小距离（单位：米）" ,example = "50")
        private Double minDistanceToLake;

        /**
         * 与居住区最小距离（单位：米）
         * 要求库区位置到最近居民区的最小安全距离。
         * 比如：1000 米以内不能建油库。
         */
        @Schema(description  = "与居住区最小距离（单位：米）" ,example = "20")
        private Double minDistanceToResidential;

        /**
         * 与机场中心点最小距离（单位：米）
         * 库区选址位置到机场中心点的最小距离。
         * 比如：3000 米以内不能建油库，保证飞行安全。
         */
        @Schema(description  = "与机场中心点最小距离（单位：米）" ,example = "700")
        private Double minDistanceToAirportCenter;

        public void check(Double rangePointDistance) {
            if (minDistanceToReservoir != null && minDistanceToReservoir >= rangePointDistance){
                throw new IllegalArgumentException("与水库最小距离不能大于jc范围");
            }
            if (minDistanceToLake != null && minDistanceToLake >= rangePointDistance){
                throw new IllegalArgumentException("与湖泊最小距离不能大于jc范围");
            }
            if (minDistanceToResidential != null && minDistanceToResidential >= rangePointDistance){
                throw new IllegalArgumentException("与居住区最小距离不能大于jc范围");
            }
            if (minDistanceToAirportCenter != null && minDistanceToAirportCenter >= rangePointDistance){
                throw new IllegalArgumentException("与机场中心点最小距离不能大于jc范围");
            }
        }

    }

}
